

/***********************************************
*   Project: Virtual Manufacturing System      *
*                                              *
*   Date: 03.08.12                             *
*                                              *
*   File: VisualElement.h                      *
*                                              *
*   Author: Rafal Pielech                      *
*   E-mail: rafalpielech@hotmail.com           *
************************************************/

#ifndef VISUAL_ELEMENT_H
#define VISUAL_ELEMENT_H

// OpenGL headers must be included before this file
#include "velData.h"
#include <string.h>


template < class VTK_real , class VTK_integer > class VisualElement
{
   protected:
              velData< VTK_real , VTK_integer > * elementData;

              short stateFlag;
              
              static unsigned int vtkObjectsCounter;
              
              unsigned int vtkDisplayListID;
              
    public:
              VisualElement( void );

              short           vtkGood       ( void );
              void            vtkInitElement( const string fname , const float  * color = NULL );

              void            vtkTransformEl( const VTK_real * matrix );

              void            vtkShowElement( void );

              virtual void    vtkCompileDisplayList( void ) = 0;

              virtual        ~VisualElement ( void );
};

// --------------------------------------------------------------------------------
// ------------------------ < Implementation > ------------------------------------

template < class VTK_real , class VTK_integer >
VisualElement< VTK_real , VTK_integer > :: VisualElement( void )
{
        elementData = NULL;
        stateFlag   = 1;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
short
VisualElement< VTK_real , VTK_integer > :: vtkGood( void )
{
        return stateFlag;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
VisualElement< VTK_real , VTK_integer > :: vtkInitElement( const string fname , const float * color )
{
        elementData->vtkLoadGeometry( fname );

        stateFlag = elementData->vtkGood(); // if stateFlag is set to 0 it means that elementData faild and is ready
                                            // to get another file to initialize visual element

        if( !stateFlag ) return;
 
        if( color != NULL ) elementData->vtkSetColor( color );
        vtkCompileDisplayList();
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
VisualElement< VTK_real , VTK_integer > :: vtkTransformEl( const VTK_real * matrix )
{
      elementData->vtkTransformObject( matrix );
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
VisualElement< VTK_real , VTK_integer > :: vtkShowElement( void )
{

      if( stateFlag )
      {
            glPushMatrix();
              glMultMatrixd( elementData->vtkGetTransMatrix() );
             
               glCallList( vtkDisplayListID ); // OpenGL routine calls unique display list
               
            glPopMatrix();
      }
      
     else return;
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
VisualElement< VTK_real , VTK_integer > :: ~VisualElement( void )
{
        delete elementData;
}

// --------------------------------------------------------------------------------
template < class VTK_real , class VTK_integer > unsigned int VisualElement< VTK_real , VTK_integer > :: vtkObjectsCounter = 0;
// --------------------------------------------------------------------------------

// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
class VisualElementTri : public VisualElement< VTK_real , VTK_integer >
{
        public:
                   VisualElementTri( void );
                   VisualElementTri( const string fname );

                   void vtkCompileDisplayList( void );
};

// --------------------------------------------------------------------------------
// ------------------------ < Implementation > ------------------------------------

template < class VTK_real , class VTK_integer >
VisualElementTri< VTK_real , VTK_integer > :: VisualElementTri( void )
{
        elementData = new velData_tri< VTK_real , VTK_integer >();
        
        vtkDisplayListID = ++vtkObjectsCounter; // increment display list identification number
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
VisualElementTri< VTK_real , VTK_integer > :: VisualElementTri( const string fname )
{
        elementData = new velData_tri< VTK_real , VTK_integer >();

        vtkDisplayListID = ++vtkObjectsCounter; // increment display list identification number
        vtkInitElement( fname );
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
VisualElementTri< VTK_real , VTK_integer > :: vtkCompileDisplayList( void )
{

        VTK_integer Index_1;

        const VTK_real    ** vertices = elementData->vtkGetVerticesArray();
        const VTK_real    ** normalv  = elementData->vtkGetNormalvArray();
        const VTK_integer ** indices  = elementData->vtkGetIndicesArray();

        const float * color = elementData->vtkGetColor();
        
        const float specualar_reflect[]  = { 0.8 , 0.8 , 0.8 , 1.0 };
        float ambient_property[4];
        
        for( Index_1 = 0; Index_1 < 4; Index_1++ ) // color attenuation
        {
            ambient_property[ Index_1 ] = color[ Index_1 ] - 0.40;
            
            if( ambient_property[ Index_1 ] < 0.0 ) ambient_property[ Index_1 ] = 0.0;
        }
        
        const_cast< const float * >( ambient_property );
               
        VTK_integer nOfFaces = elementData->vtkGetNofFaces();
        
        glNewList( vtkDisplayListID , GL_COMPILE ); // this function assumes that specified VTK_real is double ... !!!

            glMaterialfv( GL_FRONT , GL_AMBIENT  , ambient_property  );
            glMaterialfv( GL_FRONT , GL_DIFFUSE  , color             );
            glMaterialfv( GL_FRONT , GL_SPECULAR , specualar_reflect );
            glMaterialf ( GL_FRONT , GL_SHININESS , 50 );

               for( Index_1 = 0; Index_1 < nOfFaces; Index_1++ )
               {

                    glBegin( GL_TRIANGLES );

                        glNormal3dv( normalv[ Index_1 ] );
 
                             glVertex3dv( vertices[ indices[ Index_1 ][ 0 ] ] );
                             glVertex3dv( vertices[ indices[ Index_1 ][ 1 ] ] );
                             glVertex3dv( vertices[ indices[ Index_1 ][ 2 ] ] );
 
                    glEnd();
               }
        
        glEndList();
}

// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
class VisualElementPoly : public VisualElement< VTK_real , VTK_integer >
{
        public:
                   VisualElementPoly( void );
                   VisualElementPoly( const string fname );

                   void vtkCompileDisplayList( void );
};

// --------------------------------------------------------------------------------
// ------------------------ < Implementation > ------------------------------------

template < class VTK_real , class VTK_integer >
VisualElementPoly< VTK_real , VTK_integer > :: VisualElementPoly( void )
{
        elementData = new velData_poly< VTK_real , VTK_integer >();
        vtkDisplayListID = ++vtkObjectsCounter; // increment display list identification number
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
VisualElementPoly< VTK_real , VTK_integer > :: VisualElementPoly( const string fname )
{
        elementData = new velData_poly< VTK_real , VTK_integer >();
        vtkDisplayListID = ++vtkObjectsCounter; // increment display list identification number
        vtkInitElement( fname );
}

// --------------------------------------------------------------------------------

template < class VTK_real , class VTK_integer >
void
VisualElementPoly< VTK_real , VTK_integer > :: vtkCompileDisplayList( void )
{

      VTK_integer Index_1 , Index_2;
      
        const VTK_real    ** vertices = elementData->vtkGetVerticesArray();
        const VTK_real    ** normalv  = elementData->vtkGetNormalvArray();
        const VTK_integer ** indices  = elementData->vtkGetIndicesArray();

        const float * color = elementData->vtkGetColor();
        
        const float specualar_reflect[]  = { 0.8 , 0.8 , 0.8 , 1.0 };
        float ambient_property[4];
        
        for( Index_1 = 0; Index_1 < 4; Index_1++ ) // color attenuation
        {
            ambient_property[ Index_1 ] = color[ Index_1 ] - 0.40;
            
            if( ambient_property[ Index_1 ] < 0.0 ) ambient_property[ Index_1 ] = 0.0;
        }
        
        const_cast< const float * >( ambient_property );
               
        VTK_integer nOfFaces = elementData->vtkGetNofFaces();
        
        glNewList( vtkDisplayListID , GL_COMPILE ); // this function assumes that specified VTK_real is double ... !!!

            glMaterialfv( GL_FRONT , GL_AMBIENT  , ambient_property  );
            glMaterialfv( GL_FRONT , GL_DIFFUSE  , color             );
            glMaterialfv( GL_FRONT , GL_SPECULAR , specualar_reflect );
            glMaterialf ( GL_FRONT , GL_SHININESS , 50 );

        
               for( Index_1 = 0; Index_1 < nOfFaces; Index_1++ )
               {

                    glBegin( GL_POLYGON );

                        glNormal3dv( normalv[ Index_1 ] );
                             
                             for( Index_2 = 0; Index_2 < indices[ Index_1 ][ 0 ]; Index_2++ )
                             {
                                  glVertex3dv( vertices[ indices[ Index_1 ][ Index_2 + 1 ] ] );
                             }
                             
                     glEnd();
               }
        
        glEndList();
      
}

// --------------------------------------------------------------------------------
#endif